package org.pisces.wechat.config;

import static org.springframework.util.ObjectUtils.isEmpty;

import java.io.IOException;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.io.ResolverUtil;
import org.apache.ibatis.io.VFS;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
import org.pisces.wechat.enums.EnumIdentifiable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 标签信息 <br>
 * 创建日期：2017/8/1 <br>
 * <b>Copyright 2017 UTSOFT All Rights Reserved</b>
 * @author 罗朕中 <zhen-zhong.luo@utsoft.cn>
 * @version 1.0
 * @since 1.0
 */
public class MybatisSqlSessionFactoryBean extends SqlSessionFactoryBean {
	// private TypeHandler<?>[] typeHandlers;
	private Logger LOG = LoggerFactory.getLogger(getClass());
	private List<Handler> handlers;
	private SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

	/**
	 * Set type handlers. They must be annotated with {@code MappedTypes} and optionally with
	 * {@code MappedJdbcTypes}
	 * @param handlers Type handler list
	 * @since 1.0.1
	 */
	public void setTypeHandlers(List<Handler> handlers) {
		this.handlers = handlers;
	}
	@Override
	protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
		SqlSessionFactory sqlSessionFactory = super.buildSqlSessionFactory();
		Configuration configuration = sqlSessionFactory.getConfiguration();
		if (!isEmpty(this.handlers)) {
			for (Handler handler : handlers) {
				this.scanEnums(configuration, handler.getScanPkg(), handler.getTypeHandlerClass());
			}
		}
		return this.sqlSessionFactoryBuilder.build(configuration);
	}
	private void scanEnums(Configuration configuration, String basePackage, Class<?> handlerClass) {
		if (StringUtils.isBlank(basePackage) || handlerClass == null)
			return;
		VFS.addImplClass(SpringBootVFS.class);
		ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
		resolverUtil.find(new ResolverUtil.IsA(EnumIdentifiable.class), basePackage);
		Set<Class<? extends Class<?>>> mTypes = resolverUtil.getClasses();
		for (Class<?> javaTypeClass : mTypes) {
			LOG.info("className :  {}", javaTypeClass.getName());
			registerEnumHandler(configuration, javaTypeClass, handlerClass);
		}
	}
	private void registerEnumHandler(Configuration configuration, Class<?> javaTypeClass, Class<?> handlerClass) {
		if (javaTypeClass == EnumIdentifiable.class) {
			return;
		}
		TypeHandlerRegistry registry = configuration.getTypeHandlerRegistry();
		registry.register(javaTypeClass, handlerClass);
	}

	public static class Handler {
		private String scanPkg;
		private Class<?> typeHandlerClass;

		public String getScanPkg() {
			return scanPkg;
		}
		public void setScanPkg(String scanPkg) {
			this.scanPkg = scanPkg;
		}
		public Class<?> getTypeHandlerClass() {
			return typeHandlerClass;
		}
		public void setTypeHandlerClass(Class<?> typeHandlerClass) {
			this.typeHandlerClass = typeHandlerClass;
		}
	}
}
